import * as React from "react";
import Taro from "@tarojs/taro";
import {HomeShape, LoadingScreenShape} from "@/data/home/homeTypes";
import {CourseFilterShape, CourseListShape, CourseListShapeFilter} from "@/data/courses/courseTypes";
import {ShopItemListingShape} from "@/data/shop/shopItemListingTypes";
import {TalkShape} from "@/data/talks/talkTypes";
import {ApiShopItemsMapping, ShopDataShape} from "@/data/shop/shopTypes";
import {AboutShape} from "@/data/about/aboutTypes";
import {ExhibitionListingShape} from "@/data/exhibitions/exhibitionTypes";
import {GiftCertificateShape} from "@/data/user/userTypes";
import {ItemTypes, PagesNavigation} from "@/data/pages/pagesTypes";
import {CheckoutModalShape} from "@/data/order/orderTypes";
import {DiscoverTabsEnum} from "@/pages/discover/discoverData";
import {DateShape, TimeShape} from "@/data/shared/timeTypes";
import {apiWithAuth} from "./authContext";

export const enum ModalTypes {
  None,
  QR,
  Cancel,
  CancelSuccess,
  CancelFail,
  Review,
  Refund,
  Login,
  GiftedEvent,
  WaitingListReady,
  InvoiceConfirmation,
  BookingInfoSummary,
  PrivacyTerms,
}

type ModalWithDataTypes = ModalTypes.GiftedEvent | ModalTypes.WaitingListReady;
export type DataModalPayloadShape = {
  modal: ModalWithDataTypes;
  title: string;
  name: string;
  content?: {
    name: string;
    timeInfo: {
      date: DateShape;
      startTime: TimeShape;
      endTime: TimeShape;
    };
  }[];
  primaryCta: { text: string; callback: () => void };
  secondaryCta?: { text: string; callback: () => void };
  bottomText: string[];
};

type ShareDataShape = {
  text?: string;
  imagePath?: string;
  url?: PagesNavigation;
  shared?: boolean;
};

type ErrorMessage = { errorMsg: string };
export type ApplicationAction =
  | { type: "FETCH_FAIL"; data?: never; error: ErrorMessage }
  | { type: "FETCHING"; data?: never; error?: never }
  | { type: "LOADING_SCREEN_SUCCESS"; data: LoadingScreenShape; error?: never }
  | { type: "HOME_SUCCESS"; data: HomeShape; error?: never }
  | {
  type: "COURSES_SUCCESS";
  data: { courses: CourseListShape; filterParams: CourseFilterShape, filterCourses: CourseListShapeFilter };
  error?: never;
}
  | {
  type: "PUBLICATIONS_SUCCESS";
  data: ShopItemListingShape[];
  error?: never;
}
  | {
  type: "EXHIBITIONS_SUCCESS";
  data: ExhibitionListingShape;
  error?: never;
}
  | { type: "TALKS_SUCCESS"; data: TalkShape[]; error?: never }
  | { type: "SHOP_SUCCESS"; data: ShopDataShape; error?: never }
  | { type: "ABOUT_SUCCESS"; data: AboutShape; error?: never }
  | { type: "DISCOVER_TAB"; data: { tab: DiscoverTabsEnum }; error?: never }
  | {
  type: "SHOW_MODAL";
  data: Exclude<
    ModalTypes,
    ModalWithDataTypes | ModalTypes.Review | ModalTypes.BookingInfoSummary
  >;
  error?: never;
}
  | {
  type: "SHOW_DATA_MODAL";
  data: DataModalPayloadShape;
  error?: never;
}
  | {
  type: "SHOW_REVIEW_MODAL";
  data: string;
  error?: never;
}
  | {
  type: "SET_SHARE_DATA";
  data: ShareDataShape;
  error?: never;
}
  | {
  type: "SHOW_BOOKING_SUMMARY_MODAL";
  data: CheckoutModalShape;
  error?: never;
}
  | {
  type: "SET_REVIEW_ORDER_NUMBER";
  data: string | null;
  error?: never;
}
  | {
  type: "SET_INVOICE_ORDER_NUMBERS";
  data: string[];
  error?: never;
}
  | {
  type: "SELECTED_GIFT_CARD";
  data: GiftCertificateShape | null;
  error?: never;
};
type Dispatch = (action: ApplicationAction) => void;

export interface AppState {
  fetchError: null | ErrorMessage;
  fetchingData: boolean;
  loadingScreen: null | LoadingScreenShape;
  home: null | HomeShape;
  courses: CourseListShape;
  filterCourses: CourseListShapeFilter,
  courseFilterParams: CourseFilterShape | null;
  publications: ShopItemListingShape[];
  exhibitionsListing: ExhibitionListingShape | null;
  talks: TalkShape[];
  shopItems: null | ShopDataShape;
  about: null | AboutShape;
  selectedDiscoverTab: DiscoverTabsEnum;
  showModalType: ModalTypes;
  modalDataPayload: DataModalPayloadShape | null;
  reviewOrderNumber: string | null;
  selectedGiftCard: GiftCertificateShape | null;
  shareData: ShareDataShape;
  invoiceOrderNumbers: string[];
  bookingSummaryModalData: CheckoutModalShape;
}

const reducer = (
  state: AppState,
  {type, data, error}: ApplicationAction
): AppState => {
  switch (type) {
    case "FETCH_FAIL":
      return {
        ...state,
        fetchingData: false,
        fetchError: error,
      };
    case "FETCHING":
      return {
        ...state,
        fetchingData: true,
      };
    case "LOADING_SCREEN_SUCCESS":
      return {
        ...state,
        fetchingData: false,
        loadingScreen: data,
      };
    case "HOME_SUCCESS":
      return {
        ...state,
        fetchingData: false,
        home: data,
      };
    case "COURSES_SUCCESS":
      return {
        ...state,
        fetchingData: false,
        courses: data.courses,
        courseFilterParams: data.filterParams,
        filterCourses: data.filterCourses
      };
    case "PUBLICATIONS_SUCCESS":
      return {
        ...state,
        fetchingData: false,
        publications: data,
      };
    case "TALKS_SUCCESS":
      return {
        ...state,
        fetchingData: false,
        talks: data,
      };
    case "EXHIBITIONS_SUCCESS":
      return {
        ...state,
        fetchingData: false,
        exhibitionsListing: data,
      };
    case "SHOP_SUCCESS":
      return {
        ...state,
        fetchingData: false,
        shopItems: data,
      };
    case "ABOUT_SUCCESS":
      return {
        ...state,
        fetchingData: false,
        about: data,
      };
    case "DISCOVER_TAB":
      let shareData: ShareDataShape = {};
      switch (data.tab) {
        case DiscoverTabsEnum.Courses:
          shareData = {
            text: "查询L'ÉCOLE课程列表",
            imagePath: "/assets/images/sharing-courselist.jpg",
          };
          break;
        case DiscoverTabsEnum.Talks:
          shareData = {
            text: "预约L'ÉCOLE讲座",
          };
          break;
        case DiscoverTabsEnum.Exhibitions:
          shareData = {
            text: "探索L'ÉCOLE全球展览",
            imagePath: "/assets/images/sharing-exhibitionlist.jpg",
          };
          break;
        case DiscoverTabsEnum.Publications:
          shareData = {
            text: "选购L'ÉCOLE出版物",
            imagePath: "/assets/images/sharing-publicationlist.jpg",
          };
          break;
        case DiscoverTabsEnum.About:
          shareData = {
            text: "关于我们",
            imagePath: "/assets/images/sharing-aboutus.jpg",
          };
          break;

        default:
          break;
      }

      shareData.url = `pages/discover/index?id=${data.tab}`;

      return {
        ...state,
        selectedDiscoverTab: data.tab,
        shareData,
      };
    case "SHOW_MODAL":
      return {
        ...state,
        modalDataPayload: null,
        showModalType: data,
      };
    case "SHOW_REVIEW_MODAL":
      return {
        ...state,
        reviewOrderNumber: data,
        showModalType: ModalTypes.Review,
      };
    case "SHOW_BOOKING_SUMMARY_MODAL":
      return {
        ...state,
        bookingSummaryModalData: data,
        showModalType: ModalTypes.BookingInfoSummary,
      };
    case "SET_REVIEW_ORDER_NUMBER":
      return {
        ...state,
        reviewOrderNumber: data,
      };
    case "SET_INVOICE_ORDER_NUMBERS":
      return {
        ...state,
        invoiceOrderNumbers: data,
      };
    case "SHOW_DATA_MODAL":
      return {
        ...state,
        showModalType: data.modal,
        modalDataPayload: data,
      };
    case "SET_SHARE_DATA":
      return {
        ...state,
        shareData: data,
      };
    case "SELECTED_GIFT_CARD":
      return {
        ...state,
        selectedGiftCard: data,
      };
    default:
      throw new Error(`Unhandled action type: ${type}`);
  }
};

// Logic from https://dev.to/sanderdebr/flawless-react-state-management-usereducer-and-context-api-1a7g
// Action helpers

export const getLoadingScreen = async (
  dispatch: React.Dispatch<ApplicationAction>
) => {
  dispatch({type: "FETCHING"});
  try {
    const response = await Taro.request({
      url: `${process.env.apiEndpoint}/home/background`,
    });

    if (response.data.code !== 200) {
      throw Error(response.data.message);
    }

    let {routine_home_background} = response.data.data;
    if (routine_home_background.length) {
      dispatch({
        type: "LOADING_SCREEN_SUCCESS",
        data: routine_home_background[0],
      });
    }
    return true;
  } catch (error) {
    dispatch({type: "FETCH_FAIL", error});
    return false;
  }
};

export const getHome = async (dispatch: React.Dispatch<ApplicationAction>) => {
  dispatch({type: "FETCHING"});
  try {
    const response = await Taro.request({
      url: `${process.env.apiEndpoint}/home/getConfig`,
    });

    if (response.data.code !== 200) {
      throw Error(response.data.message);
    }

    dispatch({
      type: "HOME_SUCCESS",
      data: response.data.data as HomeShape,
    });

    return true;
  } catch (error) {
    dispatch({type: "FETCH_FAIL", error});
    return false;
  }
};

export type CourseApiParams = {
  // All strings comma separated values
  courseDurationIds?: string;
  courseInterval?: `${DateShape},${DateShape}`; // Always a range, even when only one date
  courseLanguageIds?: string;
  coursePriceIds?: string;
  courseTypeIds?: string;
};

export const getCourses = async (
  dispatch: React.Dispatch<ApplicationAction>,
  params?: CourseApiParams
) => {
  dispatch({type: "FETCHING"});

  let paramString = "";

  // Build up parameter string
  if (params) {
    const paramEntries = Object.entries(params);
    if (paramEntries.length) {
      paramString = paramEntries.reduce((accParamString, currentEntry) => {
        const [key, value] = currentEntry;
        if (accParamString.length === 1) {
          return `${accParamString}${key}=${value}`;
        } else {
          return `${accParamString}&${key}=${value}`;
        }
      }, "?");
    }
  }

  try {
    const responseArr = await Promise.all([
      // CourseList
      Taro.request({
        url: `${process.env.apiEndpoint}/vcaCourse/list${paramString}`,
      }),
      // Filter parameters
      Taro.request({
        url: `${process.env.apiEndpoint}/home/course/config`,
      }),

    ]);

    responseArr.forEach((response) => {
      if (response.data.code !== 200) {
        throw Error(response.data.message);
      }
    });

    const [courseResponse, filterResponse] = responseArr;

    if (courseResponse.data.code === 200) {
      // 假设 courseResponse.data.data 是一个对象数组
      const ids = courseResponse.data.data.map(item => item.id).join(',');
      // 新增的接口
      Taro.request({
        url: `${process.env.apiEndpoint}/vcaCourse/listNoScheduling?courseIds=${ids}${paramString.replace('?', '&')}`,
        header: {
          'token': Taro.getStorageSync('token')
        },
        success: function (res) {
          res.data.data.forEach(item => {
            // item.noScheduling = true;
            item.type = 0;
          });

          let newCourseResponse = courseResponse.data.data;
          newCourseResponse.push(...res.data.data);
          dispatch({
            type: "COURSES_SUCCESS",
            data: {
              courses: newCourseResponse as CourseListShape,
              filterParams: filterResponse.data.data as CourseFilterShape,
              filterCourses: res.data.data as CourseListShapeFilter
            },
          });

          return true;
        }
      });
    }


  } catch (error) {
    dispatch({type: "FETCH_FAIL", error});
    return false;
  }
};


// Note: limit data in API call, eventually may support fetching more
export const getShopItemsOfType = async (
  type: ApiShopItemsMapping,
  dispatch: React.Dispatch<ApplicationAction>
) => {
  try {
    const response = await Taro.request({
      url: `${process.env.apiEndpoint}/product/page/list/${type}`,
    });

    if (response.data.code !== 200) {
      throw Error(response.data.message);
    }

    const responseList = response.data.data.list as ShopItemListingShape[];
    // Only caching of publications
    if (type === ApiShopItemsMapping.Publication) {
      dispatch({
        type: "PUBLICATIONS_SUCCESS",
        data: responseList,
      });
    }

    return responseList;
  } catch (error) {
    dispatch({type: "FETCH_FAIL", error});
    return false;
  }
};

// Note: limit data in API call, eventually may support fetching more
export const getTalks = async (dispatch: React.Dispatch<ApplicationAction>) => {
  dispatch({type: "FETCHING"});
  try {
    const response = await Taro.request({
      url: `${process.env.apiEndpoint}/talk/list`,
    });

    if (response.data.code !== 200) {
      throw Error(response.data.message);
    }

    dispatch({
      type: "TALKS_SUCCESS",
      data: response.data.data.list as TalkShape[],
    });

    return true;
  } catch (error) {
    dispatch({type: "FETCH_FAIL", error});
    return false;
  }
};

export const getExhibitions = async (
  dispatch: React.Dispatch<ApplicationAction>
) => {
  try {
    const response = await Taro.request({
      url: `${process.env.apiEndpoint}/exhibition/list`,
    });

    if (response.data.code !== 200) {
      throw Error(response.data.message);
    }

    dispatch({
      type: "EXHIBITIONS_SUCCESS",
      data: response.data.data as ExhibitionListingShape,
    });

    return true;
  } catch (error) {
    dispatch({type: "FETCH_FAIL", error});
    return false;
  }
};

export const getShop = async (dispatch: React.Dispatch<ApplicationAction>) => {
  try {
    const response = await Taro.request({
      url: `${process.env.apiEndpoint}/product/list`,
    });

    if (response.data.code !== 200) {
      throw Error(response.data.message);
    }

    dispatch({
      type: "SHOP_SUCCESS",
      data: response.data.data as ShopDataShape,
    });

    return true;
  } catch (error) {
    dispatch({type: "FETCH_FAIL", error});
    return false;
  }
};

export const getAbout = async (dispatch: React.Dispatch<ApplicationAction>) => {
  dispatch({type: "FETCHING"});
  try {
    const response = await Taro.request({
      url: `${process.env.apiEndpoint}/about/get`,
    });

    if (response.data.code !== 200) {
      throw Error(response.data.message);
    }

    const {data} = response.data;

    const filteredAbout = {
      ...data,
      carouselMap: data.base.carouselMap,
      title: data.base.title,
      heroSubPageId: data.base.id,
      introduction: data.base.introduction,
      subPages: data.list,
      //schools: data.centre
    };

    dispatch({type: "ABOUT_SUCCESS", data: filteredAbout});
    return true;
  } catch (error) {
    dispatch({type: "FETCH_FAIL", error});
    return false;
  }
};

export const getSubAbout = async (id) => {
  const response = await Taro.request({
    url: `${process.env.apiEndpoint}/about/getAbout?id=${id}`,
  });

  if (response.data.code !== 200) {
    throw Error(response.data.message);
  }

  const {data} = response.data;

  return data;
};

// @ts-ignore
const ApplicationContext = React.createContext<{
  applicationState: AppState;
  dispatch: Dispatch;
  getSingleDetailPage: (type: ItemTypes, id: number) => Promise<any>;
}>();

function ApplicationProvider({children}) {
  const [applicationState, dispatch] = React.useReducer(reducer, {
    fetchError: null,
    fetchingData: false,
    loadingScreen: null,
    home: null,
    courses: [],
    filterCourses: [],
    courseFilterParams: null,
    publications: [],
    talks: [],
    exhibitionsListing: null,
    selectedDiscoverTab: DiscoverTabsEnum.Courses,
    shopItems: null,
    about: null,
    showModalType: ModalTypes.None,
    modalDataPayload: null,
    reviewOrderNumber: null,
    selectedGiftCard: null,
    shareData: {},
    invoiceOrderNumbers: [],
    bookingSummaryModalData: {},
  });

  // FOR API CALLS WITH ID
  const getSingleDetailPage = async (type: ItemTypes, id: number) => {
    dispatch({type: "FETCHING"});
    try {
      let url = "";
      console.log(type, "==============type=================")
      switch (type) {
        case "course":
          url = `/vcaCourse/info?courseId=${id}`;
          break;
        case "bundlecourse":
          url = `/vcaCourse/package/info?coursePackageId=${id}`;
          break;
        case "talk":
          url = `/talk/info?talkId=${id}`;
          break;
        case "exhibition":
          url = `/exhibition/info?exhibitionId=${id}`;
          break;
        case "shopitem":
          url = `/product/info/${id}`;
          break;

        default:
          break;
      }

      return await apiWithAuth(url, (response) => response.data.data);
    } catch (error) {
      dispatch({type: "FETCH_FAIL", error});
    }
  };

  const value = {applicationState, dispatch, getSingleDetailPage};
  return (
    <ApplicationContext.Provider value={value}>
      {children}
    </ApplicationContext.Provider>
  );
}

function useApplicationInfo() {
  const context = React.useContext(ApplicationContext);
  if (context === undefined) {
    throw new Error(
      "useApplicationInfo must be used within a ApplicationProvider"
    );
  }
  return context;
}

export {ApplicationProvider, useApplicationInfo};
